﻿/*
 * Разработчик: Коледа Андрей
 * Дата: 20.01.2011
 * Время: 11:04
 * Email: koleda.andrey@gmail.com
 */
using System;
using System.Collections.Generic;
using System.Linq;
using FastTravel.DataAccess.Base;
using FastTravel.DataAccess.Interface;
using FastTravel.DB;
using FastTravel.DB.Enums;
using FastTravel.Utilites;
using StructureMap;

namespace FastTravel.BusinessLogic
{
	/// <summary>
	/// Управление пользователями
	/// </summary>
	public static class UserManager
	{
		/// <summary>
		/// Хранилище пользователей
		/// </summary>
		private static IRepository<User> UserRepository
		{
			get{return ObjectFactory.GetInstance<IRepository<User>>();}
		}

		/// <summary>
		/// Хранилище заказов
		/// </summary>
		private static IRepository<Order> OrderRepository
		{
			get { return ObjectFactory.GetInstance<IRepository<Order>>(); }
		}

		/// <summary>
		/// Создание пользователя
		/// </summary>
		/// <param name="login">Имя пользователя</param>
		/// <param name="password">Пароль</param>
		/// <param name="userRole">Роль пользователя</param>
		/// <param name="firstName">Имя</param>
		/// <param name="lastName">Фамилия</param>
		/// <param name="middleName">Отчество</param>
		/// <param name="isBlocked">Пользователь заблокирован</param>
		/// <returns>Пользователь</returns>
		public static User Add(string login, string password, UserRole userRole,
			string firstName, string lastName, string middleName, bool isBlocked)
		{
			if (!string.IsNullOrEmpty(login) && !string.IsNullOrEmpty(password))
			{
				string passwordSalt = PasswordHelper.GeneratePasswordSalt();
				string passwordHash = PasswordHelper.HashPassword(password, passwordSalt);

				var user = new User
							   {
								   Login = login,
								   PasswordHash = passwordHash,
								   PasswordSalt = passwordSalt,
								   IsBlocked = isBlocked,
								   UserRole = userRole,
								   IsArchive = false,
								   AddedDate = DateTime.Now,
								   FirstName = firstName,
								   LastName = lastName,
								   MiddleName = middleName,
								   IsOnline = false
							   };
				UserRepository.Add(user);
				return user;
			}
			return null;
		}

		/// <summary>
		/// Обновление данных о пользователе
		/// </summary>
		/// <param name="userId">ID пользователя</param>
		/// <param name="login">Имя пользователя (логин)</param>
		/// <param name="password">Пароль</param>
		/// <param name="userRole">Роль</param>
		/// <param name="firstName">Имя</param>
		/// <param name="lastName">Фамилия</param>
		/// <param name="middleName">Отчество</param>
		/// <param name="isBlocked">Пользователь заблокирован</param>
		public static void Update(int userId, string login, string password, UserRole userRole,
			string firstName, string lastName, string middleName, bool isBlocked)
		{
			User user = UserRepository.Single(x => x.ID == userId);
			if (user != null)
			{
				if (!string.IsNullOrWhiteSpace(login) && !string.IsNullOrWhiteSpace(password))
				{
					string passwordSalt = PasswordHelper.GeneratePasswordSalt();
					string passwordHash = PasswordHelper.HashPassword(password, passwordSalt);

					user.Login = login;
					user.PasswordHash = passwordHash;
					user.PasswordSalt = passwordSalt;
					user.IsBlocked = isBlocked;
					user.UserRole = userRole;
					user.IsArchive = false;
					user.FirstName = firstName;
					user.LastName = lastName;
					user.MiddleName = middleName;

					UserRepository.SaveChanges();
				}
			}
		}

		/// <summary>
		/// Обновление данных о пользователе
		/// </summary>
		/// <param name="userId">ID пользователя</param>
		/// <param name="login">Имя пользователя (логин)</param>
		/// <param name="userRole">Роль</param>
		/// <param name="firstName">Имя</param>
		/// <param name="lastName">Фамилия</param>
		/// <param name="middleName">Отчество</param>
		/// <param name="isBlocked">Пользователь заблокирован</param>
		public static void Update(int userId, string login, UserRole userRole,
			string firstName, string lastName, string middleName, bool isBlocked)
		{
			User user = UserRepository.Single(x => x.ID == userId);
			if (user != null)
			{
				if (!string.IsNullOrWhiteSpace(login))
				{
					user.Login = login;
					user.IsBlocked = isBlocked;
					user.UserRole = userRole;
					user.IsArchive = false;
					user.FirstName = firstName;
					user.LastName = lastName;
					user.MiddleName = middleName;

					UserRepository.SaveChanges();
				}
			}
		}

		/// <summary>
		/// Получить пользователя
		/// </summary>
		/// <param name="id">ID</param>
		/// <returns>Пользователь</returns>
		public static User Get(int id)
		{
			return UserRepository.Single(x => x.ID == id);
		}

		/// <summary>
		/// Получить объект по имени пользователя
		/// </summary>
		/// <param name="login">Имя пользователя</param>
		/// <returns>Пользователь</returns>
		public static User Get(string login)
		{
			if (!string.IsNullOrWhiteSpace(login))
			{
				return UserRepository.GetQuery().Where(u => ((u.IsArchive == false) && (u.Login == login.Trim()))).FirstOrDefault();
			}
			return null;
		}

		/// <summary>
		/// Получить всех пользователей
		/// </summary>
		/// <returns>Список пользователей</returns>
		public static IEnumerable<User> GetAll(bool showDeleted)
		{
			return !showDeleted ? UserRepository.GetQuery().Where(x => x.IsArchive == false) : UserRepository.GetAll();
		}

		/// <summary>
		///  Получить страницу пользователей
		/// </summary>
		/// <param name="start">Начальная страница</param>
		/// <param name="limit">Размер страницы</param>
		/// <param name="sort">Сортировка по полю</param>
		/// <param name="dir">Направление сортировки</param>
		/// <param name="count">Общее число пользователей</param>
		/// <returns>Список пользователей</returns>
		public static List<User> GetPage(int start, int limit, string sort, string dir, out int count)
		{
			return UserRepository.GetPage(start, limit, sort, dir, out count);
		}

		/// <summary>
		///  Получить страницу пользователей
		/// </summary>
		/// <param name="start">Начальная страница</param>
		/// <param name="limit">Размер страницы</param>
		/// <param name="sort">Сортировка по полю</param>
		/// <param name="dir">Направление сортировки</param>
		/// <param name="showIsArchive">Показать удаленных</param>
		/// <param name="count">Общее число пользователей</param>
		/// <returns>Список пользователей</returns>
		public static List<User> GetPage(int start, int limit, string sort, string dir, bool showIsArchive, out int count)
		{
			if (showIsArchive)
			{
				return UserRepository.GetPage(start, limit, sort, dir, out count);
			}

			var result = UserRepository.GetQuery().Where(x => x.IsArchive == false).Select(e => e);
			if (!string.IsNullOrEmpty(sort))
			{
				result = sort == "ASC"
							? UserRepository.SortByQuery<User>(result, sort, true)
							: UserRepository.SortByQuery<User>(result, sort, false);
			}

			if (start >= 0 && limit > 0)
			{
				result = result.Skip(start).Take(limit);
			}
			count = UserRepository.GetQuery().Where(x => x.IsArchive == false).Count();

			return result.ToList();
		}

		/// <summary>
		/// Получить количество пользователей
		/// </summary>
		/// <returns>Количество</returns>
		public static int Count()
		{
			return UserRepository.GetQuery().Count();
		}

		/// <summary>
		/// Получить количнство пользователей учитывая/не учитывыя удаленных
		/// </summary>
		/// <param name="showIsArchive">TRUE - отображать удаленных пользователей</param>
		/// <returns>Количество</returns>
		public static int Count(bool showIsArchive)
		{
			return showIsArchive ? 
					UserRepository.GetQuery().Where(x => x.IsArchive == true).Count() 
					: UserRepository.GetQuery().Count();
		}

		/// <summary>
		/// Удалить пользователя
		/// </summary>
		/// <param name="userId">ID</param>
		/// <param name="removeFromDb">TRUE - удалить навсегда, FALSE - поментить как архивный</param>
		public static void Delete(int userId, bool removeFromDb)
		{
			User user = UserRepository.Single(x => x.ID == userId);
			if (user != null)
			{
				if (removeFromDb)
				{
					UserRepository.Delete(user);
				}
				else
				{
					user.IsArchive = true;
				}
			}
		}

		/// <summary>
		/// Проверка на сущестование заказов у пользователя
		/// </summary>
		/// <param name="userId">ID пользователя</param>
		/// <returns>TRUE - если есть</returns>
		public static bool HasOrder (int userId)
		{
			int orderCount = UserRepository.GetQuery().Where(c => c.Order.Any(x => x.User.ID == userId)).Count();
			return orderCount > 0;
		}

		/// <summary>
		/// Сменить пароль для пользователя
		/// </summary>
		/// <param name="userId">ID пользователя</param>
		/// <param name="newPassword">Пароль</param>
		/// <returns>Пользователь</returns>
		public static User ChangePassword(int userId, string newPassword)
		{
			if (!string.IsNullOrWhiteSpace(newPassword))
			{
				User user = UserRepository.Single(x => x.ID == userId);
				if (user != null)
				{
					user.PasswordSalt = PasswordHelper.GeneratePasswordSalt();
					user.PasswordHash = PasswordHelper.HashPassword(newPassword, user.PasswordSalt);
					return user;
				}
				return null;
			}
			return null;
		}

		/// <summary>
		/// Проверка пользователя на существование в БД
		/// </summary>
		/// <param name="login">Имя пользователя</param>
		/// <returns>TRUE - существует</returns>
		public static bool IsExsist(string login)
		{
			if (!string.IsNullOrEmpty(login))
			{
					User user = UserRepository.Single(x => x.Login == login.Trim());
					if (user != null)
					{
						return true;
					}
			}
			return false;
		}

		/// <summary>
		/// Проверка пользователя
		/// </summary>
		/// <param name="login"></param>
		/// <param name="password"></param>
		/// <returns></returns>
		public static bool Validate(string login, string password)
		{
			if (!string.IsNullOrWhiteSpace(login) || !string.IsNullOrWhiteSpace(password))
			{
				User user = UserRepository.Single(x => x.Login == login);
			  
				if (user != null)
				{
					if (user.IsBlocked)
					{
						return false;
					}
					if (user.IsArchive)
					{
						return false;
					}
					string passwordHash = PasswordHelper.HashPassword(password,  user.PasswordSalt);
					return passwordHash == user.PasswordHash;
				}
			}
			return false;
		}

		/// <summary>
		/// Блокировка/разблокировка пользователя
		/// </summary>
		/// <param name="id">ID пользователя</param>
		/// <param name="blocking">Блокировать/разблокировать</param>
		public static void Block(int id, bool blocking)
		{
			User user = UserRepository.Single(x => x.ID == id);
			if (user != null)
			{
				user.IsBlocked = blocking;
			}
		}

		/// <summary>
		/// Блокировка/разблокировка пользователя
		/// </summary>
		/// <param name="login">Имя пользователя</param>
		/// <param name="blocking">Блокировать/разблокировать</param>
		public static User Block (string login, bool blocking)
		{
			User user = UserRepository.Single(x => x.Login == login);
			if (user != null)
			{
				user.IsBlocked = blocking;
				return user;
			}
			return null;
		}
	}
}
